package org.easy.eao.spring.schema;

import static org.easy.eao.spring.SpringEaoFactory.DEFAULT_ACTIONS_NAME;
import static org.easy.eao.spring.SpringEaoFactory.DEFAULT_EAO_BUILDER_NAME;

import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.easy.eao.spring.DefaultActionSet;
import org.easy.eao.spring.SpringEaoBuilder;
import org.easy.eao.spring.SpringEaoFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class ConfigDefinitionParser implements BeanDefinitionParser {
	
	/** 日志对象 */
	static final Logger logger = LoggerFactory.getLogger(ConfigDefinitionParser.class);
	
	private EaoBeanDefinitionParser eaoParser = new EaoBeanDefinitionParser();
	private DefaultActionsDefinitionParser actionParser = new DefaultActionsDefinitionParser();
	private ScanEaoDefinitionParser scanParser = new ScanEaoDefinitionParser();
	
	@Override
	public BeanDefinition parse(Element element, ParserContext parserContext) {
		
		/* Element是当前解析到的XML元素。
		 * ParserContext 是 BeanDefinitionParser 的相关上下文环境。它在整个 Bean 的定义和解析过程中一直存在，它包含着全部相关的配置和状态信息。
		 * 自从 Spring 2.5 开始，就可以使用 GenericBeanDefinition来替代 RootBeanDefinition 来完成Bean的定义和注册，它在完成父依赖方法更有优势。
		 */
		BeanDefinitionRegistry registry = parserContext.getRegistry();
		registerDefaultBuilder(registry);
		String defaultAction = registerDefaultActions(element, parserContext);

		NodeList child = element.getChildNodes();
		for (int i = 0; i < child.getLength(); i++) {
			Node node = child.item(i);
			if (node.getNodeType() != Node.ELEMENT_NODE)
				continue;
			
			String name = node.getLocalName();
			// 自动包扫描处理
			if (name.equals(EaoSchemaNames.SCAN_PACKAGES_ELEMENT)) {
				Set<BeanDefinitionHolder> beanDefinitions = scanParser.parse((Element) node, parserContext);
				for (BeanDefinitionHolder holder : beanDefinitions) {
					String beanName = holder.getBeanName();
					BeanDefinition eaoBean = holder.getBeanDefinition();
					eaoBean.getPropertyValues().addPropertyValue(
							new PropertyValue(SpringEaoFactory.ATTRIBUTE_DEFAULT_ACTIONS_NAME, defaultAction));
					registry.registerBeanDefinition(beanName, eaoBean);
				}
				continue;
			}
			
			// XML定义处理
			if (name.equals(EaoSchemaNames.BEAN_ELEMENT)) {
				BeanDefinition eaoBean = eaoParser.parse((Element) node, parserContext);
				eaoBean.getPropertyValues().addPropertyValue(
						new PropertyValue(SpringEaoFactory.ATTRIBUTE_DEFAULT_ACTIONS_NAME, defaultAction));
				String beanName = ((Element) node).getAttribute(EaoSchemaNames.BEAN_ATTRIBUTE_ID);
				registry.registerBeanDefinition(beanName, eaoBean);
			}
		}
		
		return null;
	}
	
	/**
	 * 注册默认 Action 集合
	 * @param element
	 * @param parserContext
	 * @return
	 */
	private String registerDefaultActions(Element element, ParserContext parserContext) {
		BeanDefinitionRegistry registry = parserContext.getRegistry();
		// Eao 的类型 Hibernate 或 JPA
		EaoType type = EaoType.valueOf(element.getAttribute(EaoSchemaNames.CONFIG_ATTRIBUTE_TYPE));
		// 获取正确的默认 Action 集合名称
		String beanName = element.getAttribute(EaoSchemaNames.CONFIG_ATTRIBUTE_DEFAULT_ACTIONS_NAME);
		if (StringUtils.isBlank(beanName))
			beanName = DEFAULT_ACTIONS_NAME;
		
		BeanDefinition defaultActions = null;
		NodeList child = element.getChildNodes();
		for (int i = 0; i < child.getLength(); i++) {
			// 寻找用户自己定义的默认 Action 集合
			Node node = child.item(i);
			if (node.getNodeType() != Node.ELEMENT_NODE)
				continue;
			if (((Element) node).getLocalName().equals(EaoSchemaNames.DEFAULT_ACTIONS_ELEMENT)) {
				defaultActions = actionParser.parse((Element) node, parserContext);
				break;
			}
		}
		
		if (defaultActions == null) {
			// 采用系统内定的 Action 集合
			BeanDefinitionBuilder factory = BeanDefinitionBuilder.genericBeanDefinition(DefaultActionSet.class);
			factory.addPropertyValue(DefaultActionSet.ATTRIBUTE_CLASSES, type.getDefaultActions());
			defaultActions = factory.getBeanDefinition();
		}
		registry.registerBeanDefinition(beanName, defaultActions);	
		return beanName;
	}
	
	/**
	 * 注册默认的 Eao Builder
	 * @param registry
	 */
	private void registerDefaultBuilder(BeanDefinitionRegistry registry) {
		if (registry.containsBeanDefinition(DEFAULT_EAO_BUILDER_NAME)) {
			logger.debug("默认 Eao Builder 已经存在！");
			return;
		}
		GenericBeanDefinition defaultBuilderDef = new GenericBeanDefinition();
		defaultBuilderDef.setBeanClass(SpringEaoBuilder.class);
		registry.registerBeanDefinition(DEFAULT_EAO_BUILDER_NAME, defaultBuilderDef);
		logger.debug("注册默认的 Eao Builder");
	}
	
}
